﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using LitJson;
using UnityEngine;
using System.Collections.Generic;

namespace facepp.detection
{


    /// <summary>
    /// Face++ detect api(检测人脸信息)
    /// </summary>
    public class Facepp_detect
    {
        public const string version = "v2.0";

        #region 单例
        private static Facepp_detect _instance = null;
        /// <summary>
        /// 实现单例模式
        /// </summary>
        public static Facepp_detect instance
        {

            get
            {
                if (_instance == null)
                {
                    _instance = new Facepp_detect();
                }
                return _instance;
            }
        }
        #endregion


        /// <summary>
        /// api_key
        /// </summary>
        public string api_key = "";
        /// <summary>
        /// api_secret
        /// </summary>
        public string api_secret = "";


        private const string URL = "http://apicn.faceplusplus.com/v2/detection/detect";


        #region 获取face++ 数据(通过图片链接)
        /// <summary>
        ///  获取face++ 数据 ,调用之前请先设置好api_key和api_secret
        /// </summary>
        /// <param name="imgUrl">待检测图片的URL </param>
        /// <param name="mode">检测模式可以是normal(默认) 或者 oneface 。在oneface模式中，检测器仅找出图片中最大的一张脸。</param>
        /// <param name="async">如果置为true，该API将会以异步方式被调用；也就是立即返回一个session id，稍后可通过/info/get_session查询结果。默认值为false。</param>
        /// <param name="tag">可以为图片中检测出的每一张Face指定一个不包含^@,&=*'"等非法字符且不超过255字节的字符串作为tag，tag信息可以通过 /info/get_face 查询</param>
		/// <param name="api_key">api_key </param>
		/// <param name="api_secret">api_secret</param> 
		/// <returns>face++ 数据</returns>
		public FaceDetectData getFaceDetectData(string api_key,string api_secret,string imgUrl, string mode = Mode.ONEFACE, bool async = false, string tag = "A")
        {
            //创建哈希表
            IDictionary<object, object> h = new Dictionary<object, object>();          
            h.Add("api_key", api_key);
            h.Add("api_secret", api_secret);
            h.Add("url", imgUrl);
            h.Add("mode", mode);
            h.Add("async", async);
            h.Add("tag", tag);
            h.Add("attribute", "glass,pose,gender,age,race,smiling");

            //获取服务器返回的信息
            string json = HttpHelper.CreatePostHttpText(URL, h, null);

            //解码
            JsonData obj = JsonMapper.ToObject(json);
            FaceDetectData faceData = new FaceDetectData();
            faceData.copyObject(obj);
            return faceData;
        }
		/// <summary>
		///  获取face++ 数据 ,调用之前请先设置好api_key和api_secret
		/// </summary>
		/// <param name="imgUrl">待检测图片的URL </param>
		/// <param name="mode">检测模式可以是normal(默认) 或者 oneface 。在oneface模式中，检测器仅找出图片中最大的一张脸。</param>
		/// <param name="async">如果置为true，该API将会以异步方式被调用；也就是立即返回一个session id，稍后可通过/info/get_session查询结果。默认值为false。</param>
		/// <param name="tag">可以为图片中检测出的每一张Face指定一个不包含^@,&=*'"等非法字符且不超过255字节的字符串作为tag，tag信息可以通过 /info/get_face 查询</param>
		/// <returns>face++ 数据</returns>
		public FaceDetectData getFaceDetectData(string imgUrl, string mode = Mode.ONEFACE, bool async = false, string tag = "A")
		{
			//创建哈希表
			return getFaceDetectData(this.api_key,this.api_secret,imgUrl,mode,async,tag);
		}
		#endregion
		
		#region  获取face++ 数据(post 图片二进制)
		/// <summary>
		///  获取face++ 数据 ,调用之前请先设置好api_key和api_secret
		/// </summary>
		/// <param name="byt">待检测图片的二进制</param>
        /// <param name="mode">检测模式可以是normal(默认) 或者 oneface 。在oneface模式中，检测器仅找出图片中最大的一张脸。</param>
        /// <param name="async">如果置为true，该API将会以异步方式被调用；也就是立即返回一个session id，稍后可通过/info/get_session查询结果。默认值为false。</param>
        /// <param name="tag">可以为图片中检测出的每一张Face指定一个不包含^@,&=*'"等非法字符且不超过255字节的字符串作为tag，tag信息可以通过 /info/get_face 查询</param>
        /// <returns>face++ 数据</returns>
		public FaceDetectData getFaceDetectData(string api_key,string api_secret,byte[] byt, string mode = "normal", bool async = false, string tag = "")
        {
            //创建哈希表
            IDictionary<object, object> h = new Dictionary<object, object>();
            h.Add("api_key", api_key);
            h.Add("api_secret", api_secret);
            h.Add("mode", mode);
            h.Add("async",async);
            h.Add("tag", tag);
            h.Add("attribute", "glass,pose,gender,age,race,smiling");
          
            //获取服务器信息
            string json = (HttpHelper.CreatePostHttpText(URL, h, byt));   
            //解码
            FaceDetectData faceData = new FaceDetectData();
            try
            {
                JsonData obj = JsonMapper.ToObject(json);
                faceData.copyObject(obj);  
            }
            catch (Exception e)
            {
                Debug.Log(e.ToString());
               
            }
                      
            return faceData;

        }

		public FaceDetectData getFaceDetectData(byte[] byt, string mode = "normal", bool async = false, string tag = "")
		{

			return getFaceDetectData(this.api_key,this.api_secret,byt,mode,async,tag);
		}
			#endregion

    }
	#region FaceDetectData 得到的数据 
	public class FaceDetectData
	{
		private List<Face> _faces = new List<Face>();
		private double _img_width = 0;
		private double _img_height = 0;
		private string _img_id = "";
		private string _session_id="";
		private string _url = "";
		
		
		
		/// <summary>
		/// 脸部信息集合
		/// </summary>
		public List<Face> faces
		{
			get { return _faces; }
		}
		
		/// <summary>
		/// 请求图片的宽度
		/// </summary>
		public double img_width
		{
			get { return _img_width; }
		}
		/// <summary>
		/// 请求图片的高度
		/// </summary>
		public double img_height
		{
			get { return _img_height; }
		}
		/// <summary>
		/// Face++系统中的图片标识符，用于标识用户请求中的图片
		/// </summary>
		public string img_id
		{
			get { return _img_id; }
		}
		/// <summary>
		/// 相应请求的session标识符，可用于结果查询
		/// </summary>
		public string session_id
		{
			get { return _session_id; }
		}
		/// <summary>
		/// 请求中图片的url(如果是二进制请求的,将为空)
		/// </summary>
		public string url
		{
			get { return _url; }
		}
		
		internal void copyObject(JsonData obj)
		{
			
			JsonData faceArray=obj["face"];
			for (int i = 0; i < faceArray.Count; i++)
			{
				Face face = new Face();
				face.copyObject(faceArray[i]);
				_faces.Add(face);
			}
			
			_img_width = (double) obj["img_width"];
			_img_height = (double) obj["img_height"];
			_img_id = (string) obj["img_id"];
			_session_id = (string) obj["session_id"];
			if (obj["url"] != null)
			{
				_url = (string)obj["url"];
			}
			
			
		}
		
		public string toJson()
		{
			return JsonMapper.ToJson(this);
		}
		
	}
	#endregion


	#region Face
	public class Face
	{
		private string _face_id;
		private string _tag;
		private Attribute _attribute = null;
		private Position _position = null;
		
		
		/// <summary>
		/// 被检测出的每一张人脸都在Face++系统中的标识符
		/// </summary>
		public string face_id
		{
			get { return _face_id; }
		}
		
		/// <summary>
		/// tag
		/// </summary>
		public string tag
		{
			get { return _tag; }
		}
		
		/// <summary>
		/// 脸部属性信息
		/// </summary>
		public Attribute attribute
		{
			get { return _attribute; }
		}
		/// <summary>
		/// 一些器官的位置信息
		/// </summary>
		public Position position
		{
			get { return _position; }
		}
		
		internal void copyObject(JsonData obj)
		{
			_attribute = new Attribute();
			_position = new Position();
			
			_attribute.copyObject(obj["attribute"]);
			_position.copyObject(obj["position"]);
			
			_face_id = (string)obj["face_id"];
			_tag = (string)obj["tag"];
		}
		
	}
	#endregion 
	#region Attribute 脸部属性 
	public class Attribute
	{

		public const string AGE="age";
		public const string GENDER="gender";
		public const string GLASS="glass";
		public const string POSE="pose";
		public const string RACE="race";
		public const string SMILING="smiling";

		private Age _age = new Age();
		private Gender _gender = new Gender();
		private Glass _glass = new Glass();
		private Pose _pose = new Pose();
		private Race _race = new Race();
		private Smiling _smiling = new Smiling();
		private IDictionary<string ,JsonData> _dictionrys=null;
		
		/// <summary>
		/// 年龄
		/// </summary>
		public Age age{	get {return _age; }}
		/// <summary>
		/// 性别
		/// </summary>
		public Gender gender{get { return _gender; }}
		/// <summary>
		/// 眼镜佩戴信息
		/// </summary>
		public Glass glass{get { return _glass; }}
		/// <summary>
		/// 脸部姿势
		/// </summary>
		public Pose pose{	get { return _pose; }}
		
		/// <summary>
		/// 人种
		/// </summary>
		public Race race{get { return _race; }}
		/// <summary>
		/// 微笑程度
		/// </summary>
		public Smiling smiling{get { return _smiling; }}

		internal void copyObject(JsonData obj)
		{
			_dictionrys=obj.Inst_Object;

			if(_dictionrys[AGE]!=null){
				_age.copyObject((JsonData)_dictionrys[AGE]);
			}
			if(_dictionrys[GENDER]!=null){
				_gender.copyObject((JsonData)_dictionrys[GENDER]);
			}

			if(_dictionrys[GLASS]!=null){
				_glass.copyObject((JsonData)_dictionrys[GLASS]);
			}
			if(_dictionrys[POSE]!=null){
				_pose.copyObject((JsonData)_dictionrys[POSE]);
			}

			if(_dictionrys[RACE]!=null){
				_race.copyObject((JsonData)_dictionrys[RACE]);
			}

			if(_dictionrys[SMILING]!=null){
				_smiling.copyObject((JsonData)_dictionrys[SMILING]);
			}
		}
	}
	#endregion

	 #region Age 包含年龄分析结果，value的值为一个非负整数表示估计的年龄, range表示估计年龄的正负区间
	public class Age
	{
		private double _range = 0;
		private double _value = 0;
		
		/// <summary>
		/// 表示估计年龄的正负区间
		/// </summary>
		public double  range
		{
			get { return _range; }
		}
		
		/// <summary>
		/// 估计年龄
		/// </summary>
		public double value
		{
			get { return _value; }
		}
		
		
		internal void copyObject(JsonData obj)
		{
			
			_range = (double)obj["range"];
			_value = (double)obj["value"];
		}
		
		
	}
	#endregion

	#region Gender 包含性别分析结果，value的值为Male/Female, confidence表示置信度
	public class Gender
	{
		/// <summary>
		/// 男性
		/// </summary>
		public const string MALL = "Mail";
		/// <summary>
		/// 女性
		/// </summary>
		public  const string FEMALL = "Female";
		
		
		
		private double _confidence = 0;
		private string _value = "";
		
		/// <summary>
		/// 可信度
		/// </summary>
		public double confidence
		{
			get { return _confidence; }
		}
		
		/// <summary>
		/// 男性还是女性  (type: Gender.Mall)
		/// </summary>
		public string value
		{
			get { return _value; }
		}
		
		
		
		internal  void copyObject(JsonData obj)
		{
			_confidence = (double)obj["confidence"];
			_value =(string) obj["value"];
		}
	}
	#endregion

	#region Glass 含眼镜佩戴分析结果，value的值为None/Dark/Normal, confidence表示置信度
	public class Glass
	{
		/// <summary>
		/// 未佩戴
		/// </summary>
		public const string NONE = "None";
		/// <summary>
		/// 黑超
		/// </summary>
		public  const string DARK = "Drak";
		/// <summary>
		/// 普通眼镜
		/// </summary>
		public const string NORMAL = "Normal";

		private double _confidence = 0;
		private string _value = "";
		
		
		
		/// <summary>
		/// 可信度
		/// </summary>
		public double confidence
		{
			get { return _confidence; }
		}
		
		/// <summary>
		/// 佩戴眼镜？ (type : Glass.None)
		/// </summary>
		public string value
		{
			get { return _value; }
		}
		internal void copyObject(JsonData obj)
		{
			_confidence = (double)obj["confidence"];
			_value  =(string) obj["value"];
		}
	}
	#endregion
	

	#region Pose 包含脸部姿势分析结果，包括pitch_angle, roll_angle, yaw_angle，分别对应抬头，旋转（平面旋转），摇头。单位为角度。
	public class Pose
	{
		private double _pitch_angle = 0;
		private double _roll_angle = 0;
		private double _yaw_angle = 0;
		
		/// <summary>
		/// 抬头角度
		/// </summary>
		public double pitch_angle
		{
			get { return _pitch_angle; }
		}
		
		/// <summary>
		/// 旋转角度 
		/// </summary>
		public double roll_angle
		{
			get { return _roll_angle; }
		}
		
		/// <summary>
		/// 摇头角度
		/// </summary>
		public double yaw_angel
		{
			get { return _yaw_angle; }
		}
		
		internal void copyObject(JsonData obj)
		{
			_pitch_angle = (double)obj["pitch_angle"]["value"] ;
			_roll_angle = (double)obj["roll_angle"]["value"];
			_yaw_angle = (double)obj["yaw_angle"]["value"];
		}
	}
	#endregion
	

	#region Race 包含人种分析结果，value的值为Asian/White/Black, confidence表示置信度
	public class Race 
	{
		/// <summary>
		/// 亚洲人
		/// </summary>
		public const string ASIAN = "Asian";
		/// <summary>
		/// 白种人
		/// </summary>
		public const string White = "White";
		/// <summary>
		/// 黑种人
		/// </summary>
		public const  string Black = "Black";
		
		
		private double _confidence = 0;
		private string _value = "";
		
		
		/// <summary>
		/// 可信度
		/// </summary>
		public double confidence
		{
			get { return _confidence; }
		}
		
		/// <summary>
		/// 种族  (type：Race.ASIAN)
		/// </summary>
		public string value
		{
			get { return _value; }
		}
		
		
		internal void copyObject(JsonData obj)
		{
			
			_confidence = (double)obj["confidence"];
			_value = (string)obj["value"];
		}
		
	}
	#endregion
	
	

	#region Smiling 包含微笑程度分析结果，value的值为0－100的实数，越大表示微笑程度越高
	public class Smiling
		
	{
		private double _value = 0;
		
		
		/// <summary>
		/// 微笑指数
		/// </summary>
		public double value
		{
			get { return _value; }
		}
		internal void copyObject(JsonData obj)
		{
			_value = (double)obj["value"];
		}
	}
	#endregion

	#region Position 器官数据 
	public class Position
	{
		private double _width = 0;
		private double _height = 0;
		private OrganPosition _center = new OrganPosition();
		private OrganPosition _eye_left = new OrganPosition();
		private OrganPosition _eye_right = new OrganPosition();
		private OrganPosition _mouth_left = new OrganPosition();
		private OrganPosition _mouth_right = new OrganPosition();
		private OrganPosition _nose = new OrganPosition();
		
		/// <summary>
		/// 脸部在图片里占的宽度百分比
		/// </summary>
		public double width
		{
			get { return _width; }
		}
		
		/// <summary>
		/// 脸部在图片里占的高度百分比
		/// </summary>
		public double height
		{
			get { return _height; }
		}
		
		/// <summary>
		/// 脸部中心点
		/// </summary>
		public OrganPosition center
		{
			get { return _center; }
		}
		
		/// <summary>
		/// 左眼
		/// </summary>
		public OrganPosition eye_left
		{
			get { return _eye_left; }
		}
		/// <summary>
		/// 右眼
		/// </summary>
		public OrganPosition eye_right
		{
			get { return _eye_right; }
		}
		/// <summary>
		/// 左嘴角
		/// </summary>
		public OrganPosition mouth_left
		{
			get { return _mouth_left; }
		}
		/// <summary>
		/// 右嘴角
		/// </summary>
		public OrganPosition mouth_right
		{
			get { return _mouth_right; }
		}
		/// <summary>
		/// 鼻子
		/// </summary>
		public OrganPosition nose
		{
			get { return _nose; }
		}
		
		
		
		internal void copyObject(JsonData obj)
		{
			
			
			_width = (double)obj["width"];
			_height = (double)obj["height"];
			
			_center.copyObject(obj["center"]);
			_eye_left.copyObject(obj["eye_left"]);
			_eye_right.copyObject(obj["eye_right"]);
			_mouth_left.copyObject(obj["mouth_left"]);
			_mouth_right.copyObject(obj["mouth_right"]);
			_nose.copyObject(obj["nose"]);
			
			
		}
	}
	#endregion
	

	#region OrganPosition 器官坐标信息
	public class OrganPosition
	{
		private double _x = 0;
		private double _y = 0;
		
		
		/// <summary>
		/// 器官在脸部的百分比 X
		/// </summary>
		public double x
		{
			get { return _x; }
		}
		
		/// <summary>
		/// 器官在脸部的百分比 Y
		/// </summary>
		public double y
		{
			get { return _y; }
		}
		
		internal void copyObject(JsonData obj)
		{
			_x=(double) obj["x"];
			_y = (double)obj["y"];
		}
	}
	#endregion
	





	
	/// <summary>
	/// 检测模式
	/// </summary>
	public class Mode
	{
		public const string NORMAL = "normal";
		public const string ONEFACE = "oneface";
	}
}